package de.home.util;

import java.io.File;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Configuration extends PropertiesConfiguration {

   private final static String  CONFIG_FILE_NAME = "config.properties";
   private static final Logger  LOG              = LogManager.getLogger(Configuration.class);
   private static Configuration instance;

   private Configuration() {
      try {
         initConfiguration();
      } catch (ConfigurationException e) {
         LOG.error(e.getMessage());
      }
   }

   private void initConfiguration() throws ConfigurationException {
      File configFile = searchForConfigFile();
      if ( configFile == null ) {
         InputStream inputStream = this.getClass().getResourceAsStream(CONFIG_FILE_NAME);
         super.load(inputStream);
         LOG.info("Config file '{}' loaded from resources.", CONFIG_FILE_NAME);
      } else {
         LOG.info("Config file : '{}'", configFile.getAbsolutePath());
         super.load(configFile);
      }

      if ( getBoolean("refreshConfigFile", false) ) {
         final long refrehDelay = getLong("refrehDelay", 10000);
         FileChangedReloadingStrategy fileChangedReloadingStrategy = new FileChangedReloadingStrategy();
         fileChangedReloadingStrategy.setRefreshDelay(refrehDelay);
         this.setReloadingStrategy(fileChangedReloadingStrategy);
      }
      this.addConfigurationListener(new ConfigListener());
      if ( getBoolean("showConfig", true) )
         showConfig();
   }

   public static synchronized Configuration getInstance() {
      if ( instance == null ) {
         instance = new Configuration();
      }
      return instance;
   }

   private File searchForConfigFile() {
      File tmpFile = new File(System.getProperty("user.home") + "/" + CONFIG_FILE_NAME);
      if ( fileIsValid(tmpFile) ) {
         return tmpFile;
      }
      URL resource = this.getClass().getClassLoader().getResource(CONFIG_FILE_NAME);
      try {
         tmpFile = new File(resource.toURI());
      } catch (URISyntaxException e) {}
      if ( fileIsValid(tmpFile) ) {
         return tmpFile;
      }

      return null;

      // throw new FileNotFoundException("File '" + tmpFile +
      // "' cannot be found anywhere!");
   }

   private boolean fileIsValid(File tmpFile) {
      if ( !tmpFile.canRead() || !tmpFile.exists() || !tmpFile.isFile() ) {
         LOG.warn("File '{}' is not available or it cannot be read.", tmpFile.getAbsolutePath());
         return false;
      }
      return true;
   }

   private void showConfig() {
      if ( isEmpty() ) {
         LOG.warn("Property file is empty!");
         return;
      }

      Iterator<String> allKeys = this.getKeys();
      while (allKeys.hasNext()) {
         String propertyKey = allKeys.next();
         LOG.debug("[Property] " + propertyKey + " = " + this.getString(propertyKey));
      }
   }
}
